package net.disk;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.activation.MimetypesFileTypeMap;

import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Children;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.About;
import com.google.api.services.drive.model.ChildList;
import com.google.api.services.drive.model.ChildReference;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;

public class GoogleAccess
{
	private static String CLIENT_ID = "962901024537.apps.googleusercontent.com";
	private static String CLIENT_SECRET = "xZCYErPg3ekekGJ9M10o87TU";
	private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";

	public static void main(final String[] args)
	{
		final GoogleAccess google = new GoogleAccess();
		try {
			final File f = google.queryFile("/hi/new/hello.txt");
			google.RenameFile(f.getId(), "better.txt");
		}
		catch (final IOException e) {
			e.printStackTrace();
		}
	}

	private Drive service;

	public GoogleAccess()
	{
		final HttpTransport httpTransport = new NetHttpTransport();
		final JsonFactory jsonFactory = new JacksonFactory();
		final GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, CLIENT_ID,
				CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE)).setAccessType("online").setApprovalPrompt("auto").build();
		final String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
		System.out.println("Please type the authorization code:");
		try {
			Runtime.getRuntime().exec("/usr/bin/firefox " + url);
		}
		catch (final IOException e) {
			e.printStackTrace();
		}
		final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		try {
			final String code = br.readLine();
			final GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
			final GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
			// Create a new authorized API client
			service = new Drive.Builder(httpTransport, jsonFactory, credential).build();
		}
		catch (final IOException e) {
			e.printStackTrace();
		}
	}

	public void deleteFile(final String fileId)
	{
		try {
			service.files().delete(fileId).execute();
		}
		catch (final IOException e) {
			System.out.println("An error occurred: " + e);
		}
	}

	public InputStream downloadFile(final File file)
	{
		final String url = file.getDownloadUrl();
		if (url != null && url.length() > 0) {
			try {
				final HttpResponse resp = service.getRequestFactory().buildGetRequest(new GenericUrl(url)).execute();
				return resp.getContent();
			}
			catch (final IOException e) {
				// An error occurred.
				e.printStackTrace();
				return null;
			}
		}
		else {
			// The file doesn't have any content stored on Drive.
			return null;
		}
	}

	public String folderid()
	{
		try {
			final About about = service.about().get().execute();
			return about.getRootFolderId();
		}
		catch (final IOException e) {
			e.printStackTrace();
		}
		return "";
	}

	public File insertFile(final String title, final String description, final String parentId, String mimeType,
			final String filename, final boolean folder)
	{
		final java.io.File fileContent = new java.io.File(filename);
		if (!folder) {
			mimeType = new MimetypesFileTypeMap().getContentType(fileContent);
		}
		// File's metadata.
		final File body = new File();
		body.setTitle(title);
		body.setDescription(description);
		body.setMimeType(mimeType);
		// Set the parent folder.
		if (parentId != null && parentId.length() > 0) {
			body.setParents(Arrays.asList(new ParentReference().setId(parentId)));
		}
		// File's content.
		final FileContent mediaContent = new FileContent(mimeType, fileContent);
		try {
			final File file;
			if (!folder) {
				file = service.files().insert(body, mediaContent).execute();
			}
			else {
				file = service.files().insert(body).execute();
			}
			System.out.println("**********************");
			System.out.println(file.toPrettyString());
			System.out.println("**********************");
			return file;
		}
		catch (final IOException e) {
			System.out.println("An error occured: " + e);
			return null;
		}
	}

	public File moveFile(final String fileId, final String id)
	{
		try {
			final File file = new File();
			file.setParents(Arrays.asList(new ParentReference().setId(id)));
			// Move the file.
			final com.google.api.services.drive.Drive.Files.Patch patchRequest = service.files().patch(fileId, file);
			patchRequest.setFields("parents");
			final File updatedFile = patchRequest.execute();
			System.out.println("**********************");
			System.out.println(updatedFile.toPrettyString());
			System.out.println("**********************");
			return updatedFile;
		}
		catch (final IOException e) {
			System.out.println("An error occurred: " + e);
			return null;
		}
	}

	public List<File> queryChildren(final String path) throws IOException
	{
		final String[] directorys = ("root" + path).split("/");
		String parentid = folderid();
		final List<File> result = new ArrayList<File>();
		for (int i = 0; i < directorys.length; i++) {
			if (i == directorys.length - 1) {
				final Children.List request = service.children().list(parentid).setQ("trashed = false");
				do {
					try {
						final ChildList children = request.execute();
						for (final ChildReference child : children.getItems()) {
							final File file = service.files().get(child.getId()).execute();
							result.add(file);
						}
						request.setPageToken(children.getNextPageToken());
					}
					catch (final IOException e) {
						System.out.println("An error occurred: " + e);
						request.setPageToken(null);
					}
				}
				while (request.getPageToken() != null && request.getPageToken().length() > 0);
			}
			else {
				final Children.List request = service.children().list(parentid)
						.setQ("title = '" + directorys[i + 1] + "' and trashed = false");
				do {
					try {
						final ChildList children = request.execute();
						for (final ChildReference child : children.getItems()) {
							parentid = child.getId();
						}
						request.setPageToken(children.getNextPageToken());
					}
					catch (final IOException e) {
						System.out.println("An error occurred: " + e);
						request.setPageToken(null);
					}
				}
				while (request.getPageToken() != null && request.getPageToken().length() > 0);
			}
		}
		return result;
	}

	public File queryFile(final String path) throws IOException
	{
		final String[] directorys = path.split("/");
		String parentid = folderid();
		for (int i = 0; i < directorys.length; i++) {
			final Children.List request = service.children().list(parentid)
					.setQ("title = '" + directorys[i] + "' and trashed = false");
			do {
				try {
					final ChildList children = request.execute();
					for (final ChildReference child : children.getItems()) {
						parentid = child.getId();
						if (i == directorys.length - 1) {
							final File file = service.files().get(child.getId()).execute();
							return file;
						}
					}
					request.setPageToken(children.getNextPageToken());
				}
				catch (final IOException e) {
					System.out.println("An error occurred: " + e);
					request.setPageToken(null);
				}
			}
			while (request.getPageToken() != null && request.getPageToken().length() > 0);
		}
		return null;
	}

	public File RenameFile(final String fileId, final String newname)
	{
		try {
			final File file = new File();
			file.setTitle(newname);
			// Rename the file.
			final com.google.api.services.drive.Drive.Files.Patch patchRequest = service.files().patch(fileId, file);
			patchRequest.setFields("title");
			final File updatedFile = patchRequest.execute();
			System.out.println("**********************");
			System.out.println(updatedFile.toPrettyString());
			System.out.println("**********************");
			return updatedFile;
		}
		catch (final IOException e) {
			System.out.println("An error occurred: " + e);
			return null;
		}
	}

	public Long totalbytes()
	{
		try {
			final About about = service.about().get().execute();
			return about.getQuotaBytesTotal();
		}
		catch (final IOException e) {
			e.printStackTrace();
		}
		return (long) 0;
	}

	public File trashFile(final String fileId)
	{
		try {
			return service.files().trash(fileId).execute();
		}
		catch (final IOException e) {
			System.out.println("An error occurred: " + e);
		}
		return null;
	}

	public File updateFile(final String fileId, final String newTitle, final String newDescription, String newMimeType,
			final String newFilename, final boolean newRevision)
	{
		try {
			final java.io.File fileContent = new java.io.File(newFilename);
			newMimeType = new MimetypesFileTypeMap().getContentType(fileContent);
			// First retrieve the file from the API.
			final File file = service.files().get(fileId).execute();
			// File's new metadata.
			file.setTitle(newTitle);
			file.setDescription(newDescription);
			if (!file.getMimeType().equals("application/vnd.google-apps.folder")) {
				file.setMimeType(newMimeType);
			}
			// File's new content.
			final FileContent mediaContent = new FileContent(newMimeType, fileContent);
			// Send the request to the API.
			final File updatedFile = service.files().update(fileId, file, mediaContent).execute();
			System.out.println("**********************");
			System.out.println(updatedFile.toPrettyString());
			System.out.println("**********************");
			return updatedFile;
		}
		catch (final IOException e) {
			System.out.println("An error occurred: " + e);
			return null;
		}
	}

	public long usedbytes()
	{
		try {
			final About about = service.about().get().execute();
			return about.getQuotaBytesUsed();
		}
		catch (final IOException e) {
			e.printStackTrace();
		}
		return 0;
	}
}
